#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    //chdir("/home/oy");    //系统调用 更改进程中cwd 也就是进程启动路径 更改后那么当下边的fopen 所要创建的log.txt 没有表明所要创建的目录时，会默认使用cwd 路径
    //FILE* fp = fopen("log.txt","w");
    //if(!fp) perror("fopen");
    //fclose(fp);
    //
    //while(1)
    //{
    //    //pid_t id = getpid();    //getpid 的返回类型pid_t 就是int 类型的
    //    //printf("我是一个进程：pid：%d\n",id);
    //    //sleep(1);
    //
    //    printf("myprocess: pid : %d , ppid : %d\n",getpid(),getppid());
    //    //fork();        //通过代码 直接系统调用的方式创建一个子进程
    //    //
    //    //printf("myprocess(fork): pid : %d , ppid : %d\n",getpid(),getppid());  //由于fork 之后 变为两个进程流(执行流) 因此此行printf 会打印两次
    //    sleep(1);

    //}



    //父子进程对同一份代码：父进程的代码有确实来源，来自磁盘，而由父进程创建的子进程则没有，因此其也看父进程的代码，而要做到父子进程分开执行一份代码，那么通过fork 不同的返回值做分支即可
    printf("我是父进程，pid：%d，ppid：%d\n",getpid(),getppid());

    pid_t id = fork();     //如果fork 函数创建子进程成功，那么存在两个返回值，对于父进程会返回其创建的子进程的pid，而对于子进程则会返回0；而如果创建子进程失败，那么父进程会被返回-1，不会创建子进程
    if(id < 0 )
    {
        return 1;
    }else if(id == 0)    //对于子进程 fork 返回0
    {
        while(1)
        {
            printf("我是子进程，pid：%d，ppid：%d，id：%d\n",getpid(),getppid(),id);
            sleep(1);
        }
    }else{                //对于父进程 fork 返回其进程所创建子进程的pid 即一个正数 ; 而父进程 fork 返回其所创建的子进程的pid就是为了对子进程进行回收，而所谓的回收也就是对子进程的PCB 进行接收信号等结束进程的信息，从而使子进程从僵尸Z 状态，转变成终止D 状态
                 
        while(1)
        {
            printf("我是父进程，pid：%d，ppid：%d，id：%d\n",getpid(),getppid(),id);
            sleep(1);
        }
    }



    //进程从运行状态到阻滞状态
    //int a = 0;
    //scanf("%d",&a);        //由于scanf 会等待键盘的输入，因此进程的pcd 会从cpu 的运行队列中抽离出来，被操作系统放置在硬件键盘的内核结构中的等待队列中了，因此该进程的状态，由运行状态，变为了阻滞状态
    //printf("a = %d\n",a);  //补充：每个进程的pcd 在cpu 等待的队列叫调度队列
                           //因此，本质上，所谓的运行与阻塞，就是看该进程的pcd 在谁提供的队列中！！！
                           //一个进程 需要调用谁的资源 就去谁的等待队列中 像cpu也是硬件，跟外设一样都是有等待队列的

    
    //使进程变为sleep 也就是阻滞状态
    //while(1){
    //    sleep(1);
    //}
    
    return 0;
}
